package com.errol.generic.http;

import org.springframework.http.HttpStatus;

/**
 * 灵活、安全、可扩展的 HttpService
 * 使用建造者模式构建 http 执行计划，各种请求参数都可以灵活配置
 * 内部捕获输出异常日志，返回请求失败，不会向调用者抛出异常
 * 方便扩展新的请求和响应类型，支持灵活切换第三方 HTTP 客户端工具包
 * <p>
 * 使用 {@link HttpBuilder} 构建 HttpPlan 执行计划，构建过程分为 5 个部分：
 * HttpBuilder：设置请求 url，请求方法，超时时间等参数；由 HttpBuilder.builder() 创建；
 * HttpHeaderBuilder：设置 http header 中的参数；由 httpBuilder.useXxx() 系列方法创建；
 * HttpXxxBodyBuilder：设置 http requestBody 中的参数，不同的请求体编码格式需要对应的 HttpXxxBodyBuilder；由 httpHeaderBuilder.sendXxxData() 系列方法创建；
 * HttpXxxResultBuilder：设置 http responseBody 中的响应类型，不同的响应体编码格式需要对应的 HttpXxxResultBuilder；由 httpXxxBodyBuilder.expectXxxOfYyy() 系列方法创建；
 * HttpPlan：Http 执行计划，定义请求参数和响应参数，由 {@link HttpService} 同步或异步执行；由 httpXxxResultBuilder.build() 方法创建；
 * 除了转构建过程的 useXxx() sendXxxData() expectXxxOfYyy() 系列方法，其他的参数配置方法都是 setXxx() 或 addXxx()；
 * Http 构建执行过程中的异常已经由 {@link HttpLogger} 统一处理，调用者只需根据 {@link HttpResult} 判断请求成功与否；
 * json 序列化与反序列化都使用 ObjectMapper ，且只看 property ，使用 {@link com.fasterxml.jackson.annotation.JsonProperty} 注解映射不同的 javaBean 属性和 jsonStr 属性
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2020/10/13
 * @since v
 **/
public final class HttpResult<T> {

    /**
     * http 响应 status
     */
    private final HttpStatus httpStatus;
    /**
     * http 全过程中抛出的第一个异常，异常后不会继续执行后续的逻辑
     */
    private final Exception exception;
    /**
     * http 请求成功（响应 code 200）时的结果
     */
    private final T data;

    /**
     * 请求失败的构造器
     *
     * @param httpStatus 响应状态，可能为 null 表示执行过程抛出了异常
     * @param exception  执行异常，可能为 null 表示响应状态非 code 200
     */
    public HttpResult(HttpStatus httpStatus, Exception exception) {
        this.httpStatus = httpStatus;
        this.exception = exception;
        this.data = null;
    }

    /**
     * 请求成功（响应 code 200）的构造器
     *
     * @param data null 表示没有返回值
     */
    public HttpResult(T data) {
        this.httpStatus = HttpStatus.OK;
        this.exception = null;
        this.data = data;
    }

    /**
     * 请求是否成功（response code 200）
     *
     * @return true：如果设置了接口返回类型，则 data 不为 null； false：可能异常，可能 response code != 200
     */
    public boolean isSuccess() {
        return httpStatus == HttpStatus.OK;
    }

    /**
     * 获取 response code
     *
     * @return 执行过程异常则返回 null
     */
    public HttpStatus getHttpStatus() {
        return httpStatus;
    }

    /**
     * 获取执行过程抛出的异常
     *
     * @return 参数异常或者 http 工具包异常
     */
    public Exception getException() {
        return exception;
    }

    /**
     * 获取接口返回值
     *
     * @return response code 200 时才有返回值
     */
    public T getData() {
        return data;
    }
}
